use alloc::boxed::Box;
use alloc::string::ToString;
use alloc::vec::Vec;
use alloc::{format, vec};
use core::fmt::{self, Debug, Formatter};

use aws_lc_rs::rand::SystemRandom;
use aws_lc_rs::signature::{self, EcdsaKeyPair, Ed25519KeyPair, KeyPair, RsaKeyPair};
use pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer, SubjectPublicKeyInfoDer, alg_id};

#[cfg(any(test, bench))]
use crate::crypto::CryptoProvider;
use crate::crypto::enums::SignatureScheme;
use crate::crypto::signer::{Signer, SigningKey, public_key_to_spki};
use crate::error::Error;
use crate::sync::Arc;

/// A `SigningKey` for RSA-PKCS1 or RSA-PSS.
pub(super) struct RsaSigningKey {
    key: Arc<RsaKeyPair>,
}

impl RsaSigningKey {
    fn to_signer(&self, scheme: SignatureScheme) -> RsaSigner {
        let encoding: &dyn signature::RsaEncoding = match scheme {
            SignatureScheme::RSA_PKCS1_SHA256 => &signature::RSA_PKCS1_SHA256,
            SignatureScheme::RSA_PKCS1_SHA384 => &signature::RSA_PKCS1_SHA384,
            SignatureScheme::RSA_PKCS1_SHA512 => &signature::RSA_PKCS1_SHA512,
            SignatureScheme::RSA_PSS_SHA256 => &signature::RSA_PSS_SHA256,
            SignatureScheme::RSA_PSS_SHA384 => &signature::RSA_PSS_SHA384,
            SignatureScheme::RSA_PSS_SHA512 => &signature::RSA_PSS_SHA512,
            _ => unreachable!(),
        };

        RsaSigner {
            key: self.key.clone(),
            scheme,
            encoding,
        }
    }

    const SCHEMES: &[SignatureScheme] = &[
        SignatureScheme::RSA_PSS_SHA512,
        SignatureScheme::RSA_PSS_SHA384,
        SignatureScheme::RSA_PSS_SHA256,
        SignatureScheme::RSA_PKCS1_SHA512,
        SignatureScheme::RSA_PKCS1_SHA384,
        SignatureScheme::RSA_PKCS1_SHA256,
    ];
}

impl SigningKey for RsaSigningKey {
    fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> {
        Self::SCHEMES
            .iter()
            .find(|scheme| offered.contains(scheme))
            .map(|&scheme| Box::new(self.to_signer(scheme)) as Box<dyn Signer>)
    }

    fn public_key(&self) -> Option<SubjectPublicKeyInfoDer<'_>> {
        Some(public_key_to_spki(
            &alg_id::RSA_ENCRYPTION,
            self.key.public_key(),
        ))
    }
}

impl TryFrom<&PrivateKeyDer<'_>> for RsaSigningKey {
    type Error = Error;

    /// Make a new `RsaSigningKey` from a DER encoding, in either
    /// PKCS#1 or PKCS#8 format.
    fn try_from(der: &PrivateKeyDer<'_>) -> Result<Self, Self::Error> {
        let key_pair = match der {
            PrivateKeyDer::Pkcs1(pkcs1) => RsaKeyPair::from_der(pkcs1.secret_pkcs1_der()),
            PrivateKeyDer::Pkcs8(pkcs8) => RsaKeyPair::from_pkcs8(pkcs8.secret_pkcs8_der()),
            _ => {
                return Err(Error::General(
                    "failed to parse RSA private key as either PKCS#1 or PKCS#8".into(),
                ));
            }
        }
        .map_err(|key_rejected| {
            Error::General(format!("failed to parse RSA private key: {key_rejected}"))
        })?;

        Ok(Self {
            key: Arc::new(key_pair),
        })
    }
}

impl Debug for RsaSigningKey {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.debug_struct("RsaSigningKey").finish()
    }
}

struct RsaSigner {
    key: Arc<RsaKeyPair>,
    scheme: SignatureScheme,
    encoding: &'static dyn signature::RsaEncoding,
}

impl RsaSigner {
    fn sign(&self, message: &[u8]) -> Result<Vec<u8>, Error> {
        let mut sig = vec![0; self.key.public_modulus_len()];

        let rng = SystemRandom::new();
        self.key
            .sign(self.encoding, &rng, message, &mut sig)
            .map(|_| sig)
            .map_err(|_| Error::General("signing failed".to_string()))
    }
}

impl Signer for RsaSigner {
    fn sign(self: Box<Self>, message: &[u8]) -> Result<Vec<u8>, Error> {
        (*self).sign(message)
    }

    fn scheme(&self) -> SignatureScheme {
        self.scheme
    }
}

impl Debug for RsaSigner {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.debug_struct("RsaSigner")
            .field("scheme", &self.scheme)
            .finish()
    }
}

/// A [`SigningKey`] and [`Signer`] implementation for ECDSA.
///
/// Unlike [`RsaSigningKey`]/[`RsaSigner`], where we have one key that supports
/// multiple signature schemes, we can use the same type for both traits here.
#[derive(Clone)]
pub(super) struct EcdsaSigner {
    key: Arc<EcdsaKeyPair>,
    scheme: SignatureScheme,
}

impl EcdsaSigner {
    /// Make a new [`EcdsaSigner`] from a DER encoding in PKCS#8 or SEC1
    /// format, expecting a key usable with precisely the given signature scheme.
    fn new(
        der: &PrivateKeyDer<'_>,
        scheme: SignatureScheme,
        sigalg: &'static signature::EcdsaSigningAlgorithm,
    ) -> Result<Self, ()> {
        let key_pair = match der {
            PrivateKeyDer::Sec1(sec1) => {
                EcdsaKeyPair::from_private_key_der(sigalg, sec1.secret_sec1_der())
                    .map_err(|_| ())?
            }
            PrivateKeyDer::Pkcs8(pkcs8) => {
                EcdsaKeyPair::from_pkcs8(sigalg, pkcs8.secret_pkcs8_der()).map_err(|_| ())?
            }
            _ => return Err(()),
        };

        Ok(Self {
            key: Arc::new(key_pair),
            scheme,
        })
    }

    fn sign(&self, message: &[u8]) -> Result<Vec<u8>, Error> {
        let rng = SystemRandom::new();
        self.key
            .sign(&rng, message)
            .map_err(|_| Error::General("signing failed".into()))
            .map(|sig| sig.as_ref().into())
    }
}

impl SigningKey for EcdsaSigner {
    fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> {
        if offered.contains(&self.scheme) {
            Some(Box::new(self.clone()))
        } else {
            None
        }
    }

    fn public_key(&self) -> Option<SubjectPublicKeyInfoDer<'_>> {
        let id = match self.scheme {
            SignatureScheme::ECDSA_NISTP256_SHA256 => alg_id::ECDSA_P256,
            SignatureScheme::ECDSA_NISTP384_SHA384 => alg_id::ECDSA_P384,
            SignatureScheme::ECDSA_NISTP521_SHA512 => alg_id::ECDSA_P521,
            _ => unreachable!(),
        };

        Some(public_key_to_spki(&id, self.key.public_key()))
    }
}

impl Signer for EcdsaSigner {
    fn sign(self: Box<Self>, message: &[u8]) -> Result<Vec<u8>, Error> {
        (*self).sign(message)
    }

    fn scheme(&self) -> SignatureScheme {
        self.scheme
    }
}

impl TryFrom<&PrivateKeyDer<'_>> for EcdsaSigner {
    type Error = Error;

    /// Parse `der` as any ECDSA key type, returning the first which works.
    ///
    /// Both SEC1 (PEM section starting with 'BEGIN EC PRIVATE KEY') and PKCS8
    /// (PEM section starting with 'BEGIN PRIVATE KEY') encodings are supported.
    fn try_from(der: &PrivateKeyDer<'_>) -> Result<Self, Error> {
        if let Ok(ecdsa_p256) = Self::new(
            der,
            SignatureScheme::ECDSA_NISTP256_SHA256,
            &signature::ECDSA_P256_SHA256_ASN1_SIGNING,
        ) {
            return Ok(ecdsa_p256);
        }

        if let Ok(ecdsa_p384) = Self::new(
            der,
            SignatureScheme::ECDSA_NISTP384_SHA384,
            &signature::ECDSA_P384_SHA384_ASN1_SIGNING,
        ) {
            return Ok(ecdsa_p384);
        }

        if let Ok(ecdsa_p521) = Self::new(
            der,
            SignatureScheme::ECDSA_NISTP521_SHA512,
            &signature::ECDSA_P521_SHA512_ASN1_SIGNING,
        ) {
            return Ok(ecdsa_p521);
        }

        Err(Error::General(
            "failed to parse ECDSA private key as PKCS#8 or SEC1".into(),
        ))
    }
}

impl Debug for EcdsaSigner {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.debug_struct("EcdsaSigner")
            .field("scheme", &self.scheme)
            .finish()
    }
}

/// A [`SigningKey`] and [`Signer`] implementation for ED25519.
///
/// Unlike [`RsaSigningKey`]/[`RsaSigner`], where we have one key that supports
/// multiple signature schemes, we can use the same type for both traits here.
#[derive(Clone)]
pub(super) struct Ed25519Signer {
    key: Arc<Ed25519KeyPair>,
    scheme: SignatureScheme,
}

impl Ed25519Signer {
    fn sign(&self, message: &[u8]) -> Result<Vec<u8>, Error> {
        Ok(self.key.sign(message).as_ref().into())
    }
}

impl SigningKey for Ed25519Signer {
    fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> {
        if offered.contains(&self.scheme) {
            Some(Box::new(self.clone()))
        } else {
            None
        }
    }

    fn public_key(&self) -> Option<SubjectPublicKeyInfoDer<'_>> {
        Some(public_key_to_spki(&alg_id::ED25519, self.key.public_key()))
    }
}

impl Signer for Ed25519Signer {
    fn sign(self: Box<Self>, message: &[u8]) -> Result<Vec<u8>, Error> {
        (*self).sign(message)
    }

    fn scheme(&self) -> SignatureScheme {
        self.scheme
    }
}

impl TryFrom<&PrivatePkcs8KeyDer<'_>> for Ed25519Signer {
    type Error = Error;

    /// Parse `der` as an Ed25519 key.
    ///
    /// Note that, at the time of writing, Ed25519 does not have wide support
    /// in browsers.  It is also not supported by the WebPKI, because the
    /// CA/Browser Forum Baseline Requirements do not support it for publicly
    /// trusted certificates.
    fn try_from(der: &PrivatePkcs8KeyDer<'_>) -> Result<Self, Error> {
        match Ed25519KeyPair::from_pkcs8_maybe_unchecked(der.secret_pkcs8_der()) {
            Ok(key_pair) => Ok(Self {
                key: Arc::new(key_pair),
                scheme: SignatureScheme::ED25519,
            }),
            Err(e) => Err(Error::General(format!(
                "failed to parse Ed25519 private key: {e}"
            ))),
        }
    }
}

impl Debug for Ed25519Signer {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.debug_struct("Ed25519Signer")
            .field("scheme", &self.scheme)
            .finish()
    }
}

#[cfg(any(test, bench))]
fn load_key(
    provider: &CryptoProvider,
    der: PrivateKeyDer<'static>,
) -> Result<Box<dyn SigningKey>, Error> {
    provider
        .key_provider
        .load_private_key(der)
}

#[cfg(test)]
mod tests {
    use alloc::format;

    use pki_types::{PrivatePkcs1KeyDer, PrivateSec1KeyDer};

    use super::*;
    use crate::crypto::aws_lc_rs::DEFAULT_PROVIDER;

    #[test]
    fn can_load_ecdsa_nistp256_pkcs8() {
        let key =
            PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/nistp256key.pkcs8.der")[..]);
        assert!(Ed25519Signer::try_from(&key).is_err());
        let key = PrivateKeyDer::Pkcs8(key);
        assert!(load_key(&DEFAULT_PROVIDER, key.clone_key()).is_ok());
        assert!(EcdsaSigner::try_from(&key).is_ok());
    }

    #[test]
    fn can_load_ecdsa_nistp256_sec1() {
        let key = PrivateKeyDer::Sec1(PrivateSec1KeyDer::from(
            &include_bytes!("../../testdata/nistp256key.der")[..],
        ));
        assert!(load_key(&DEFAULT_PROVIDER, key.clone_key()).is_ok());
        assert!(EcdsaSigner::try_from(&key).is_ok());
    }

    #[test]
    fn can_sign_ecdsa_nistp256() {
        let key = PrivateKeyDer::Sec1(PrivateSec1KeyDer::from(
            &include_bytes!("../../testdata/nistp256key.der")[..],
        ));

        let k = load_key(&DEFAULT_PROVIDER, key.clone_key()).unwrap();
        assert_eq!(
            format!("{k:?}"),
            "EcdsaSigner { scheme: ECDSA_NISTP256_SHA256 }"
        );

        assert!(
            k.choose_scheme(&[SignatureScheme::RSA_PKCS1_SHA256])
                .is_none()
        );
        assert!(
            k.choose_scheme(&[SignatureScheme::ECDSA_NISTP384_SHA384])
                .is_none()
        );
        let s = k
            .choose_scheme(&[SignatureScheme::ECDSA_NISTP256_SHA256])
            .unwrap();
        assert_eq!(
            format!("{s:?}"),
            "EcdsaSigner { scheme: ECDSA_NISTP256_SHA256 }"
        );
        assert_eq!(s.scheme(), SignatureScheme::ECDSA_NISTP256_SHA256);
        // nb. signature is variable length and asn.1-encoded
        assert!(
            s.sign(b"hello")
                .unwrap()
                .starts_with(&[0x30])
        );
    }

    #[test]
    fn can_load_ecdsa_nistp384_pkcs8() {
        let key =
            PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/nistp384key.pkcs8.der")[..]);
        assert!(Ed25519Signer::try_from(&key).is_err());
        let key = PrivateKeyDer::Pkcs8(key);
        assert!(load_key(&DEFAULT_PROVIDER, key.clone_key()).is_ok());
        assert!(EcdsaSigner::try_from(&key).is_ok());
    }

    #[test]
    fn can_load_ecdsa_nistp384_sec1() {
        let key = PrivateKeyDer::Sec1(PrivateSec1KeyDer::from(
            &include_bytes!("../../testdata/nistp384key.der")[..],
        ));
        assert!(load_key(&DEFAULT_PROVIDER, key.clone_key()).is_ok());
        assert!(EcdsaSigner::try_from(&key).is_ok());
    }

    #[test]
    fn can_sign_ecdsa_nistp384() {
        let key = PrivateKeyDer::Sec1(PrivateSec1KeyDer::from(
            &include_bytes!("../../testdata/nistp384key.der")[..],
        ));

        let k = load_key(&DEFAULT_PROVIDER, key.clone_key()).unwrap();
        assert_eq!(
            format!("{k:?}"),
            "EcdsaSigner { scheme: ECDSA_NISTP384_SHA384 }"
        );

        assert!(
            k.choose_scheme(&[SignatureScheme::RSA_PKCS1_SHA256])
                .is_none()
        );
        assert!(
            k.choose_scheme(&[SignatureScheme::ECDSA_NISTP256_SHA256])
                .is_none()
        );
        let s = k
            .choose_scheme(&[SignatureScheme::ECDSA_NISTP384_SHA384])
            .unwrap();
        assert_eq!(
            format!("{s:?}"),
            "EcdsaSigner { scheme: ECDSA_NISTP384_SHA384 }"
        );
        assert_eq!(s.scheme(), SignatureScheme::ECDSA_NISTP384_SHA384);
        // nb. signature is variable length and asn.1-encoded
        assert!(
            s.sign(b"hello")
                .unwrap()
                .starts_with(&[0x30])
        );
    }

    #[test]
    fn can_load_ecdsa_nistp521_pkcs8() {
        let key =
            PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/nistp521key.pkcs8.der")[..]);
        assert!(Ed25519Signer::try_from(&key).is_err());
        let key = PrivateKeyDer::Pkcs8(key);
        assert!(load_key(&DEFAULT_PROVIDER, key.clone_key()).is_ok());
        assert!(EcdsaSigner::try_from(&key).is_ok());
    }

    #[test]
    fn can_load_ecdsa_nistp521_sec1() {
        let key = PrivateKeyDer::Sec1(PrivateSec1KeyDer::from(
            &include_bytes!("../../testdata/nistp521key.der")[..],
        ));
        assert!(load_key(&DEFAULT_PROVIDER, key.clone_key()).is_ok());
        assert!(EcdsaSigner::try_from(&key).is_ok());
    }

    #[test]
    fn can_sign_ecdsa_nistp521() {
        let key = PrivateKeyDer::Sec1(PrivateSec1KeyDer::from(
            &include_bytes!("../../testdata/nistp521key.der")[..],
        ));

        let k = load_key(&DEFAULT_PROVIDER, key.clone_key()).unwrap();
        assert_eq!(
            format!("{k:?}"),
            "EcdsaSigner { scheme: ECDSA_NISTP521_SHA512 }"
        );

        assert!(
            k.choose_scheme(&[SignatureScheme::RSA_PKCS1_SHA256])
                .is_none()
        );
        assert!(
            k.choose_scheme(&[SignatureScheme::ECDSA_NISTP256_SHA256])
                .is_none()
        );
        assert!(
            k.choose_scheme(&[SignatureScheme::ECDSA_NISTP384_SHA384])
                .is_none()
        );
        let s = k
            .choose_scheme(&[SignatureScheme::ECDSA_NISTP521_SHA512])
            .unwrap();
        assert_eq!(
            format!("{s:?}"),
            "EcdsaSigner { scheme: ECDSA_NISTP521_SHA512 }"
        );
        assert_eq!(s.scheme(), SignatureScheme::ECDSA_NISTP521_SHA512);
        // nb. signature is variable length and asn.1-encoded
        assert!(
            s.sign(b"hello")
                .unwrap()
                .starts_with(&[0x30])
        );
    }

    #[test]
    fn can_load_eddsa_pkcs8() {
        let key = PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/eddsakey.der")[..]);
        assert!(Ed25519Signer::try_from(&key).is_ok());
        let key = PrivateKeyDer::Pkcs8(key);
        assert!(load_key(&DEFAULT_PROVIDER, key.clone_key()).is_ok());
        assert!(EcdsaSigner::try_from(&key).is_err());
    }

    #[test]
    fn can_sign_eddsa() {
        let key = PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/eddsakey.der")[..]);

        let k = Ed25519Signer::try_from(&key).unwrap();
        assert_eq!(format!("{k:?}"), "Ed25519Signer { scheme: ED25519 }");

        assert!(
            k.choose_scheme(&[SignatureScheme::RSA_PKCS1_SHA256])
                .is_none()
        );
        assert!(
            k.choose_scheme(&[SignatureScheme::ECDSA_NISTP256_SHA256])
                .is_none()
        );
        let s = k
            .choose_scheme(&[SignatureScheme::ED25519])
            .unwrap();
        assert_eq!(format!("{s:?}"), "Ed25519Signer { scheme: ED25519 }");
        assert_eq!(s.scheme(), SignatureScheme::ED25519);
        assert_eq!(s.sign(b"hello").unwrap().len(), 64);
    }

    #[test]
    fn can_load_rsa2048_pkcs8() {
        let key =
            PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/rsa2048key.pkcs8.der")[..]);
        assert!(Ed25519Signer::try_from(&key).is_err());
        let key = PrivateKeyDer::Pkcs8(key);
        assert!(load_key(&DEFAULT_PROVIDER, key.clone_key()).is_ok());
        assert!(EcdsaSigner::try_from(&key).is_err());
    }

    #[test]
    fn can_load_rsa2048_pkcs1() {
        let key = PrivateKeyDer::Pkcs1(PrivatePkcs1KeyDer::from(
            &include_bytes!("../../testdata/rsa2048key.pkcs1.der")[..],
        ));
        assert!(load_key(&DEFAULT_PROVIDER, key.clone_key()).is_ok());
        assert!(EcdsaSigner::try_from(&key).is_err());
    }

    #[test]
    fn can_sign_rsa2048() {
        let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(
            &include_bytes!("../../testdata/rsa2048key.pkcs8.der")[..],
        ));

        let k = load_key(&DEFAULT_PROVIDER, key.clone_key()).unwrap();
        assert_eq!(format!("{k:?}"), "RsaSigningKey");

        assert!(
            k.choose_scheme(&[SignatureScheme::ECDSA_NISTP256_SHA256])
                .is_none()
        );
        assert!(
            k.choose_scheme(&[SignatureScheme::ED25519])
                .is_none()
        );

        let s = k
            .choose_scheme(&[SignatureScheme::RSA_PSS_SHA256])
            .unwrap();
        assert_eq!(format!("{s:?}"), "RsaSigner { scheme: RSA_PSS_SHA256 }");
        assert_eq!(s.scheme(), SignatureScheme::RSA_PSS_SHA256);
        assert_eq!(s.sign(b"hello").unwrap().len(), 256);

        for scheme in &[
            SignatureScheme::RSA_PKCS1_SHA256,
            SignatureScheme::RSA_PKCS1_SHA384,
            SignatureScheme::RSA_PKCS1_SHA512,
            SignatureScheme::RSA_PSS_SHA256,
            SignatureScheme::RSA_PSS_SHA384,
            SignatureScheme::RSA_PSS_SHA512,
        ] {
            k.choose_scheme(&[*scheme]).unwrap();
        }
    }

    #[test]
    fn cannot_load_invalid_pkcs8_encoding() {
        let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(&b"invalid"[..]));
        assert_eq!(
            load_key(&DEFAULT_PROVIDER, key.clone_key()).err(),
            Some(Error::General(
                "failed to parse private key as RSA, ECDSA, or EdDSA".into()
            ))
        );
        assert_eq!(
            EcdsaSigner::try_from(&key).err(),
            Some(Error::General(
                "failed to parse ECDSA private key as PKCS#8 or SEC1".into()
            ))
        );
        assert_eq!(
            RsaSigningKey::try_from(&key).err(),
            Some(Error::General(
                "failed to parse RSA private key: InvalidEncoding".into()
            ))
        );
    }
}

#[cfg(bench)]
mod benchmarks {
    use super::*;
    use crate::crypto::aws_lc_rs::DEFAULT_PROVIDER;

    #[bench]
    fn bench_rsa2048_pkcs1_sha256(b: &mut test::Bencher) {
        let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(
            &include_bytes!("../../testdata/rsa2048key.pkcs8.der")[..],
        ));

        let signer = RsaSigningKey::try_from(&key)
            .unwrap()
            .to_signer(SignatureScheme::RSA_PKCS1_SHA256);

        b.iter(|| {
            test::black_box(
                signer
                    .sign(SAMPLE_TLS13_MESSAGE)
                    .unwrap(),
            );
        });
    }

    #[bench]
    fn bench_rsa2048_pss_sha256(b: &mut test::Bencher) {
        let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(
            &include_bytes!("../../testdata/rsa2048key.pkcs8.der")[..],
        ));

        let signer = RsaSigningKey::try_from(&key)
            .unwrap()
            .to_signer(SignatureScheme::RSA_PSS_SHA256);

        b.iter(|| {
            test::black_box(
                signer
                    .sign(SAMPLE_TLS13_MESSAGE)
                    .unwrap(),
            );
        });
    }

    #[bench]
    fn bench_eddsa(b: &mut test::Bencher) {
        let key = PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/eddsakey.der")[..]);
        let signer = Ed25519Signer::try_from(&key).unwrap();

        b.iter(|| {
            test::black_box(
                signer
                    .sign(SAMPLE_TLS13_MESSAGE)
                    .unwrap(),
            );
        });
    }

    #[bench]
    fn bench_ecdsa_p256_sha256(b: &mut test::Bencher) {
        let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(
            &include_bytes!("../../testdata/nistp256key.pkcs8.der")[..],
        ));

        let signer = EcdsaSigner::try_from(&key).unwrap();
        b.iter(|| {
            test::black_box(
                signer
                    .sign(SAMPLE_TLS13_MESSAGE)
                    .unwrap(),
            );
        });
    }

    #[bench]
    fn bench_ecdsa_p384_sha384(b: &mut test::Bencher) {
        let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(
            &include_bytes!("../../testdata/nistp384key.pkcs8.der")[..],
        ));

        let signer = EcdsaSigner::try_from(&key).unwrap();
        b.iter(|| {
            test::black_box(
                signer
                    .sign(SAMPLE_TLS13_MESSAGE)
                    .unwrap(),
            );
        });
    }

    #[bench]
    fn bench_ecdsa_p521_sha512(b: &mut test::Bencher) {
        let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(
            &include_bytes!("../../testdata/nistp521key.pkcs8.der")[..],
        ));

        let signer = EcdsaSigner::try_from(&key).unwrap();
        b.iter(|| {
            test::black_box(
                signer
                    .sign(SAMPLE_TLS13_MESSAGE)
                    .unwrap(),
            );
        });
    }

    #[bench]
    fn bench_load_and_validate_rsa2048(b: &mut test::Bencher) {
        let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(
            &include_bytes!("../../testdata/rsa2048key.pkcs8.der")[..],
        ));

        b.iter(|| {
            test::black_box(load_key(&DEFAULT_PROVIDER, key.clone_key()).unwrap());
        });
    }

    #[bench]
    fn bench_load_and_validate_rsa4096(b: &mut test::Bencher) {
        let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(
            &include_bytes!("../../testdata/rsa4096key.pkcs8.der")[..],
        ));

        b.iter(|| {
            test::black_box(load_key(&DEFAULT_PROVIDER, key.clone_key()).unwrap());
        });
    }

    #[bench]
    fn bench_load_and_validate_p256(b: &mut test::Bencher) {
        let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(
            &include_bytes!("../../testdata/nistp256key.pkcs8.der")[..],
        ));

        b.iter(|| {
            test::black_box(EcdsaSigner::try_from(&key).unwrap());
        });
    }

    #[bench]
    fn bench_load_and_validate_p384(b: &mut test::Bencher) {
        let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(
            &include_bytes!("../../testdata/nistp384key.pkcs8.der")[..],
        ));

        b.iter(|| {
            test::black_box(EcdsaSigner::try_from(&key).unwrap());
        });
    }

    #[bench]
    fn bench_load_and_validate_p521(b: &mut test::Bencher) {
        let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(
            &include_bytes!("../../testdata/nistp521key.pkcs8.der")[..],
        ));

        b.iter(|| {
            test::black_box(EcdsaSigner::try_from(&key).unwrap());
        });
    }

    #[bench]
    fn bench_load_and_validate_eddsa(b: &mut test::Bencher) {
        let key = PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/eddsakey.der")[..]);

        b.iter(|| {
            test::black_box(Ed25519Signer::try_from(&key).unwrap());
        });
    }

    const SAMPLE_TLS13_MESSAGE: &[u8] = &[
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
        0x20, 0x20, 0x20, 0x20, 0x54, 0x4c, 0x53, 0x20, 0x31, 0x2e, 0x33, 0x2c, 0x20, 0x73, 0x65,
        0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
        0x65, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x00, 0x04, 0xca, 0xc4, 0x48, 0x0e, 0x70, 0xf2,
        0x1b, 0xa9, 0x1c, 0x16, 0xca, 0x90, 0x48, 0xbe, 0x28, 0x2f, 0xc7, 0xf8, 0x9b, 0x87, 0x72,
        0x93, 0xda, 0x4d, 0x2f, 0x80, 0x80, 0x60, 0x1a, 0xd3, 0x08, 0xe2, 0xb7, 0x86, 0x14, 0x1b,
        0x54, 0xda, 0x9a, 0xc9, 0x6d, 0xe9, 0x66, 0xb4, 0x9f, 0xe2, 0x2c,
    ];
}
